package org.szy.core.common.page;

import com.mybatisflex.core.paginate.Page;
import org.noear.solon.core.handle.Context;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;

/**
 * 通用分页请求
 *
 * @author wangbuhao
 * @date 2023-02-08
 * @since 1.0.0
 **/
public class QueryPage<T> extends Page<T> {

    private static final int INIT_VALUE = -1;

    private List<T> records = Collections.emptyList();
    private int pageNumber = INIT_VALUE; // 当前页
    private int pageSize = INIT_VALUE; // 每页条数
    private long totalPage = INIT_VALUE; // 总页数
    private long totalRow = INIT_VALUE; // 总条数
    private String ascField = ""; // 正序排序字段
    private String descField = ""; // 倒序排序字段

    public static <T> QueryPage<T> of(int pageNumber, int pageSize) {
        return new QueryPage<>(pageNumber, pageSize);
    }

    public static <T> QueryPage<T> of(int pageNumber, int pageSize, long totalRow) {
        return new QueryPage<>(pageNumber, pageSize, totalRow);
    }

    public QueryPage() {
        Context ctx = Context.current();
        // 分页参数
        this.pageNumber = ctx.paramAsInt("pageNumber", 1);
        this.pageSize = ctx.paramAsInt("pageSize", 20);
        if (this.pageNumber < 1) this.pageNumber = 1;
        if (this.pageSize < 1) this.pageSize = 1;
        if (this.pageNumber != 1) {
            this.totalPage = ctx.paramAsLong("totalPage", INIT_VALUE);
            this.totalRow = ctx.paramAsLong("totalRow", INIT_VALUE);
            if ((long) this.pageNumber * this.pageSize >= this.totalRow) {
                this.totalRow = INIT_VALUE;
            }
        }
        this.ascField = ctx.paramOrDefault("ascField", null);
        this.descField = ctx.paramOrDefault("descField", null);

    }

    public QueryPage(int pageNumber, int pageSize) {
        this.setPageNumber(pageNumber);
        this.setPageSize(pageSize);
    }

    public QueryPage(int pageNumber, int pageSize, long totalRow) {
        this.setPageNumber(pageNumber);
        this.setPageSize(pageSize);
        this.setTotalRow(totalRow);
    }


    public QueryPage(List<T> records, int pageNumber, int pageSize, long totalRow) {
        this.setRecords(records);
        this.setPageNumber(pageNumber);
        this.setPageSize(pageSize);
        this.setTotalRow(totalRow);
    }


    public List<T> getRecords() {
        return records;
    }

    public void setRecords(List<T> records) {
        if (records == null) {
            records = Collections.emptyList();
        }
        this.records = records;
    }

    public int getPageNumber() {
        return pageNumber;
    }

    public void setPageNumber(int pageNumber) {
        if (pageNumber < 1) {
            throw new IllegalArgumentException("pageNumber必须大于或等于1，当前值为: " + pageNumber);
        }
        this.pageNumber = pageNumber;
    }


    public int getPageSize() {
        return pageSize;
    }

    public void setPageSize(int pageSize) {
        if (pageSize < 0) {
            throw new IllegalArgumentException("pageSize必须大于或等于0，当前值为: " + pageSize);
        }
        this.pageSize = pageSize;
        this.calcTotalPage();
    }

    public long getTotalPage() {
        return totalPage;
    }

    public void setTotalPage(long totalPage) {
        this.totalPage = totalPage;
    }

    public long getTotalRow() {
        return totalRow;
    }

    public void setTotalRow(long totalRow) {
        if (totalRow < 0) {
            throw new IllegalArgumentException("totalRow必须大于或等于0，当前值为: " + totalRow);
        }
        this.totalRow = totalRow;
        this.calcTotalPage();
    }

    /**
     * 计算总页码
     */
    private void calcTotalPage() {
        if (totalPage == INIT_VALUE && pageSize != INIT_VALUE && totalRow != INIT_VALUE) {
            totalPage = totalRow % pageSize == 0 ? (totalRow / pageSize) : (totalRow / pageSize + 1);
        }
    }


    public <R> QueryPage<R> map(Function<? super T, ? extends R> mapper) {
        QueryPage<R> newPage = new QueryPage<>();
        newPage.pageNumber = pageNumber;
        newPage.pageSize = pageSize;
        newPage.totalPage = totalPage;
        newPage.totalRow = totalRow;

        if (records != null && !records.isEmpty()) {
            List<R> newRecords = new ArrayList<>(records.size());
            for (T t : records) {
                newRecords.add(mapper.apply(t));
            }
            newPage.records = newRecords;
        }
        return newPage;
    }

    public String getAscField() {
        return ascField;
    }

    public void setAscField(String ascField) {
        this.ascField = ascField;
    }

    public String getDescField() {
        return descField;
    }

    public void setDescField(String descField) {
        this.descField = descField;
    }

    @Override
    public String toString() {
        return "QueryPage{" +
                "pageNumber=" + pageNumber +
                ", pageSize=" + pageSize +
                ", totalPage=" + totalPage +
                ", totalRow=" + totalRow +
                ", records=" + records +
                '}';
    }


}
